// ----------------------------------------------------------------------------
// gfx_device.h
// ----------------------------------------------------------------------------
#ifndef GFX_DEVICE_H
#define GFX_DEVICE_H
#include <fw/base/core/macros.h>
#include <fw/base/core/stdint.h>
#include <fw/base/core/singleton.h>

namespace fw
{
    //
    class GfxBuffer;
    class GfxTexture;
    class GfxRenderState;
    class GfxSamplerState;
    class GfxShader;
	class GfxGeom;
    
    //
    class GfxDeviceInternal;
    class GfxTextureInternal;
	class GfxGeomInternal;
    class GfxBufferInternal;
    

    // Device Configuration. 
    class GfxDeviceConfig
    {
    private:
        
        uint32_t        m_width;
        uint32_t        m_height;
        
        bool            SanityCheck() const;
        
    public:
        
        GfxDeviceConfig( uint32_t width=512, uint32_t height=512 )
        : m_width(width)
        , m_height(height)
        {
            SanityCheck();
        }
        
        uint32_t        GetWidth() const
        {
            return m_width;
        }
        
        uint32_t        GetHeight() const
        {
            return m_height;
        }
        
    }; // class GfxDeviceConfig 
 
    // Vertex attribute format.
    enum VertexFormat
    {
        kVertexFmt_Unknown   = 0,
        kVertexFmt_F32x4,
        kVertexFmt_F32x3,
        kVertexFmt_F32x2,
        kVertexFmt_F32x1,
        kVertexFmt_F16x4,
        kVertexFmt_F16x3,
        kVertexFmt_F16x2,
        kVertexFmt_F16x1,
        kVertexFmt_S16x4N,
        kVertexFmt_S16x3N_X,
        kVertexFmt_S16x2N,
        kVertexFmt_S16x1N,
        kVertexFmt_S8x4N,
        kVertexFmt_S8x3N_X,
    }; // enum VertexFormat. 
    
    // Vertex buffer attribute. 
    enum VertexAttribute
    {
        kVertexAttrib_Static		= 0x00,
		kVertexAttrib_Dynamic		= 0x01,
		kVertexAttrib_Stream		= 0x02,
    }; // enum VertexAttribute
    
	enum IndexAttribute
	{
		kIndexAttrib_32bit			= 0x00,
		kIndexAttrib_16bit			= 0x01,
		kIndexAttrib_TriangleList	= 0x10,
		kIndexAttrib_TriangleStrip	= 0x20,
	}; // enum IndexAttribute 
	
	class GfxGeom
	{
	private:
		
		uint32_t			m_vertexCount;
		uint32_t			m_indexCount;
		VertexAttribute		m_vertexAttribute;
		IndexAttribute		m_indexAttribute;
		uint64_t			m_vertexFormat;
		
		GfxGeomInternal*	m_impl;
		
	public:
		 GfxGeom();
		~GfxGeom();
		
		int					GetVertexCount() const
		{
			return static_cast<int>(m_vertexCount);
		}

		int					GetIndexCount()  const
		{
			return static_cast<int>(m_indexCount);
		}

		int					GetVertexAttributeCount() const;
		VertexFormat		GetVertexFormat( int vertexAttributeIndex ) const;
		int					GetVertexOffset( int vertexAttributeIndex ) const;
		
	}; // class GfxGeom 
	
    // Texture format enumeration.
    enum TextureFormat
    {
        kTextureFmt_Unknown  = 0,
        kTextureFmt_ARGB8888,
        
        kTextureFmt_Mask     = 0x00ffffff,
    };

    // Texture attributes.
    enum TextureAttribute
    {
        kTextureAttr_1D   = 0x01,
        kTextureAttr_2D   = 0x02,
        kTextureAttr_3D   = 0x04,
        kTextureAttr_Cube = 0x08,
        kTextureAttr_RT   = 0x10, // Pixel shader output. 
        kTextureAttr_UAV  = 0x20, // Compute shader output. 
        kTextureAttr_Mip  = 0x40, // Contains miplevel. 
    }; // enum TextureAttribute 
    
    // Texture proxy. 
    class GfxTexture
    {
    private:
		
		friend class		GfxDevice;
		
        static const int    kTextureNameLength = 64;
        
        char                m_name[kTextureNameLength];
        
        uint16_t            m_width;
        uint16_t            m_height;
        uint16_t            m_depth;
        
        uint32_t            m_attrib; // 24bit format + 8bit attribute. 
        
        GfxTextureInternal* m_impl;
        
    public:
        
         GfxTexture();
        ~GfxTexture();
        
        const char*         GetName() const;
        
        int                 GetWidth() const
        {
            return static_cast<int>(m_width);
        }
        
        int                 GetHeight() const
        {
            return static_cast<int>(m_height);
        }

        int                 GetDepth() const
        {
            return static_cast<int>(m_depth);
        }

        uint32_t            GetFormat() const
        {
            return (m_attrib & kTextureFmt_Mask);
        }
        
        uint32_t            GetAttrib() const
        {
            return (m_attrib & ~(kTextureFmt_Mask))>>24;
        }
		
    }; // class GfxTexture 
    
    // Graphics device proxy.
    class GfxDevice : private fw::Singleton<GfxDevice>
    {
    private:
        
        GfxDeviceInternal*  m_impl;
        
    public:

         GfxDevice(const GfxDeviceConfig& config=GfxDeviceConfig());
        ~GfxDevice();
        
		GfxGeom*			CreateGeometry	();
        GfxTexture*         CreateTexture	(const char* name, uint16_t width, uint16_t height, uint32_t attr, const void* image=0);
        
        bool                PollDevice();

        bool                Flip();
        
    }; // class GfxDevice
    
} // namespace fw


#endif // GFX_DEVICE_H
